Skip to content

Conversation

@jmiguelhp
Copy link
Contributor

Originally, static routes without next hop were sent with no next_hop payload. However, there must be a next hop pointing to 0.0.0.0/0 so that APIC can set an route entry pointing to Null0 interface.

@jmiguelhp jmiguelhp marked this pull request as ready for review November 5, 2025 16:04
for node in var.nodes : [
for sr in coalesce(node.static_routes, []) : [
for nh in coalesce(sr.next_hops, []) : {
for nh in length(coalesce(sr.next_hops, [])) > 0 ? coalesce(sr.next_hops, []) : [{ ip = "0.0.0.0/0", type = "none", description = null, preference = 0, ip_sla_policy = null, track_list = null }] : {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im pretty sure this will not work because it doesnt have a key so resource should fail
could we maybe move this logic to aci_tenants.tf and pass the values there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was tested using static routes and they were pushed properly into APIC because key are defined using 0.0.0.0/0 as next hop.

Data model:

apic:
  tenants:
    - name: ABC
      l3outs:
        - name: L3OUT1
          vrf: VRF1
          domain: ROUTED1
          nodes:
            - node_id: 1001
              router_id: 5.5.5.5
              static_routes:
                - prefix: 2.2.2.0/24
                  next_hops:
                    - ip: 6.6.6.6
                - prefix: 1.1.1.1/32
                - prefix: 1.1.1.2/32

Terraform plan:

Terraform will perform the following actions:

  # module.aci.module.aci_l3out_node_profile_auto["ABC/L3OUT1"].aci_rest_managed.ipNexthopP["1001/1.1.1.1/32/0.0.0.0/0"] will be created
  + resource "aci_rest_managed" "ipNexthopP" {
      + annotation  = "orchestrator:terraform"
      + class_name  = "ipNexthopP"
      + content     = {
          + "descr"  = null
          + "nhAddr" = "0.0.0.0/0"
          + "pref"   = "unspecified"
          + "type"   = "none"
        }
      + dn          = "uni/tn-ABC/out-L3OUT1/lnodep-L3OUT1/rsnodeL3OutAtt-[topology/pod-1/node-1001]/rt-[1.1.1.1/32]/nh-[0.0.0.0/0]"
      + escape_html = true
      + id          = (known after apply)
    }

  # module.aci.module.aci_l3out_node_profile_auto["ABC/L3OUT1"].aci_rest_managed.ipNexthopP["1001/1.1.1.2/32/0.0.0.0/0"] will be created
  + resource "aci_rest_managed" "ipNexthopP" {
      + annotation  = "orchestrator:terraform"
      + class_name  = "ipNexthopP"
      + content     = {
          + "descr"  = null
          + "nhAddr" = "0.0.0.0/0"
          + "pref"   = "unspecified"
          + "type"   = "none"
        }
      + dn          = "uni/tn-ABC/out-L3OUT1/lnodep-L3OUT1/rsnodeL3OutAtt-[topology/pod-1/node-1001]/rt-[1.1.1.2/32]/nh-[0.0.0.0/0]"
      + escape_html = true
      + id          = (known after apply)
    }

Terraform apply:

Screenshot 2025-11-06 at 5 18 57 p m

Please note 0.0.0.0/0 as next hop cannot be set manually, so this creates a unique key for routes without next hop defined.

Screenshot 2025-11-06 at 5 20 33 p m

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code from PR works and key value will be set up correctly:

    for node in var.nodes : [
      for sr in coalesce(node.static_routes, []) : [
        for nh in length(coalesce(sr.next_hops, [])) > 0 ? coalesce(sr.next_hops, []) : [{ ip = "0.0.0.0/0", type = "none", description = null, preference = 0, ip_sla_policy = null, track_list = null }] : {
          key = "${node.node_id}/${sr.prefix}/${nh.ip}"

we get key based on node, static route and IP. we add missing IP in "new code".
However, I am not a big fan of adding config to an resource in main.tf. Cannot we manage it on locals level just with 0.0.0.0/0 as default value in next_hops loop?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i looked in the wrong line, however still i don't like having this in the module, where we can pass this data more safely from tenants.tf file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider that this special 0.0.0.0/0 next hop does NOT use the default values set in default file. Putting this in tenant.tf will require not only the attribute value definitions, but also conditionals to check if next_hop is 0.0.0.0/0 so that default values are not applied but hard coded.

Please confirm your preference to this approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a conditional in tenants.tf to check if next hop exists, if it does pass the old code with default values, if it doesnt exist, pass these hardcoded values
to reiterate - do not do that in the main.tf

Copy link
Contributor

@ogorczow ogorczow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR works, however could we manage it to fix via locals in next_hops?

for node in var.nodes : [
for sr in coalesce(node.static_routes, []) : [
for nh in coalesce(sr.next_hops, []) : {
for nh in length(coalesce(sr.next_hops, [])) > 0 ? coalesce(sr.next_hops, []) : [{ ip = "0.0.0.0/0", type = "none", description = null, preference = 0, ip_sla_policy = null, track_list = null }] : {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code from PR works and key value will be set up correctly:

    for node in var.nodes : [
      for sr in coalesce(node.static_routes, []) : [
        for nh in length(coalesce(sr.next_hops, [])) > 0 ? coalesce(sr.next_hops, []) : [{ ip = "0.0.0.0/0", type = "none", description = null, preference = 0, ip_sla_policy = null, track_list = null }] : {
          key = "${node.node_id}/${sr.prefix}/${nh.ip}"

we get key based on node, static route and IP. we add missing IP in "new code".
However, I am not a big fan of adding config to an resource in main.tf. Cannot we manage it on locals level just with 0.0.0.0/0 as default value in next_hops loop?

for node in var.nodes : [
for sr in coalesce(node.static_routes, []) : [
for nh in coalesce(sr.next_hops, []) : {
for nh in length(coalesce(sr.next_hops, [])) > 0 ? coalesce(sr.next_hops, []) : [{ ip = "0.0.0.0/0", type = "none", description = null, preference = 0, ip_sla_policy = null, track_list = null }] : {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a conditional in tenants.tf to check if next hop exists, if it does pass the old code with default values, if it doesnt exist, pass these hardcoded values
to reiterate - do not do that in the main.tf

@jmiguelhp jmiguelhp requested a review from juchowan November 14, 2025 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants